﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;

namespace SSP
{
    class SSPScrollingBackground : SSPNode
    {
        public Vector2 cameraPosition { get; set; }
        Vector2 screenOriginInStageSpace;
        Vector2 screenOriginInBackgroundSpace;
        int screenWidth;
        int screenHeight;
        SSPLevelDefinition data;
        int stageBuffer = 500;

        ArrayList objectsToBeDrawn;

        public SSPScrollingBackground()
        {
        }

        public SSPScrollingBackground(SSPLevelDefinition def)
        {
            screenWidth = (int)SSPDirector.Instance.windowSize().X;
            screenHeight = (int)SSPDirector.Instance.windowSize().Y;

            screenOriginInStageSpace = new Vector2(screenWidth / 2, screenHeight / 2);
            screenOriginInBackgroundSpace = cameraPosition;

            objectsToBeDrawn = new ArrayList();

            data = def;
        }

        public override void draw()
        {
            //Console.WriteLine("ScrollingBackground Draw()");
            this.updateElementPositions();
            this.drawElementsInDrawArray();
        }

        public override void update()
        {
            //Console.WriteLine("ScrollingBackground Update()");
            screenOriginInBackgroundSpace = cameraPosition;
            
            foreach (SSPSprite sp in objectsToBeDrawn)
            {
                sp.update();
            }
            this.updateDrawArray();
        }

        public Vector2 ConvertBackgroundSpaceToStageSpace(Vector2 bgSpace)
        {
            return Vector2.Add(Vector2.Subtract(bgSpace, screenOriginInBackgroundSpace), screenOriginInStageSpace);
        }

        public Vector2 ConvertStageSpaceToBackgroundSpace(Vector2 stageSpace)
        {
            return Vector2.Add(Vector2.Subtract(stageSpace, screenOriginInStageSpace), screenOriginInBackgroundSpace);
        }

        public int ConvertBackgroundSpaceToStageSpace(int bgSpace)
        {
            return (int)((bgSpace - screenOriginInBackgroundSpace.X) + screenOriginInStageSpace.X);
        }

        public int ConvertStageSpaceToBackgroundSpace(int stageSpace)
        {
            return (int)((stageSpace - screenOriginInStageSpace.X) + screenOriginInBackgroundSpace.X);
        }

        ArrayList FindElementsOnStage()
        {
            ArrayList elements = new ArrayList();

            foreach (SSPBackgroundElement obj in data.backgroundElements)
            {
                int xPos = ConvertBackgroundSpaceToStageSpace(obj.X);

                if (xPos > (0 - stageBuffer) && xPos < (screenWidth + stageBuffer))
                {
                    elements.Add(obj);
                }
            }
            
            return elements;
        }

        bool isInDrawArray(SSPSprite obj)
        {
            return objectsToBeDrawn.Contains(obj);
        }

        bool isInDrawArray(SSPBackgroundElement obj)
        {
            foreach (SSPSprite sp in objectsToBeDrawn)
            {
                if(sp.position.Equals(new Vector2(obj.X, obj.Y)))
                {
                    return true;
                }
            }
            return false;
        }

        bool isObjectOnScreen(SSPSprite obj)
        {
            if (obj.absolutePosition.X > (0 - stageBuffer) && obj.absolutePosition.X < (screenWidth + stageBuffer))
            {
                return true;
            }
            else
            {
                return false;
            }
        }

        void addElementToDrawArray(SSPBackgroundElement elementData)
        {
            foreach (SSPSprite sp in data.textureElements)
            {
                if(sp.tagName.Equals(elementData.ElementName))
                {
                    objectsToBeDrawn.Add(new SSPSprite(sp, elementData.X, elementData.Y, elementData.Scale));
                }    
            }        
        }

        void removeElementFromDrawArray(SSPSprite element)
        {
            if (objectsToBeDrawn.Contains(element))
            {
                objectsToBeDrawn.Remove(element);
            }  
        }

        void updateDrawArray()
        {
            ArrayList temp = new ArrayList();

            foreach (SSPBackgroundElement obj in this.FindElementsOnStage() )
            {
                if (!this.isInDrawArray(obj))
                {
                    this.addElementToDrawArray(obj);
                }
            }

            foreach (SSPSprite sp in objectsToBeDrawn)
            {
                if (!this.isObjectOnScreen(sp))
                {
                    temp.Add(sp);
                }
            }

            foreach (SSPSprite s in temp)
            {
                this.removeElementFromDrawArray(s);
            }

            temp.Clear();
        }

        void updateElementPositions()
        {
            foreach (SSPSprite sp in objectsToBeDrawn)
            {
                sp.absolutePosition = this.ConvertBackgroundSpaceToStageSpace(sp.position);
                //Console.WriteLine("SB Sprite {0}, AbsPos = {1},{2}  pos = {3}, cam pos = {4}", sp.scale.X, sp.absolutePosition.X, sp.absolutePosition.Y, sp.position.X, cameraPosition.X, cameraPosition.Y);
            }
        }

        void drawElementsInDrawArray()
        {
            foreach (SSPSprite sp in objectsToBeDrawn)
            {
                sp.draw();
            }
        }
    }
}
